/// pd_log 的核心 Dart API：统一日志输出、平台桥接与日志文件查询。
///
/// - 提供 `v/d/i/w/e/out` 多级别日志输出；
/// - 平台接口用于控制台输出、根路径查询与文件事件；
///   文件写入与缓冲完全由 Dart 层统一管理；
/// - 暴露日志根路径、文件列表与按日期/年份/月的查询方法；
/// - 自 0.5.0 起，日志路径结构统一为：`/<year>/<month>/<day>.log`。
import 'src/platform_service.dart';

/// 导出源码文件
import 'src/log_level.dart';
export 'src/log_level.dart';
import 'src/log_config.dart';
export 'src/log_config.dart';
import 'src/log_style_config.dart';
export 'src/log_style_config.dart';
import 'src/log_file_info.dart';
export 'src/log_file_info.dart';
import 'src/log_utils.dart';
import 'src/log_rotation.dart';
export 'src/log_rotation.dart';
import 'src/log_query.dart';
import 'src/log_ledger.dart';
import 'src/list_options.dart';
export 'src/list_options.dart';
export 'src/log_ledger.dart';
import 'src/dart_file_logger.dart';
import 'src/file_events.dart';
import 'src/file_watchers.dart';
import 'dart:io';

/// 日志工具类，提供统一的日志输出能力。
///
/// 典型使用：
/// ```dart
/// PDLog.configure(const PDLogConfig(defaultTag: 'MyApp'));
/// PDLog.d('Debug message');
/// PDLog.e('Something wrong', tag: 'Network');
/// ```
///
/// 文件写入说明：
/// - 是否写入依赖两处开关：
///   [PDLogConfig.nativeFileLoggingEnabled] 与
///   [PDLogConfig.fileLoggingMinLevel]（低于该级别不落盘）；
/// - Web 平台不支持本地文件写入，相关方法为空实现；
/// - 移动/桌面端由 Dart 写入器通过缓冲 + 定时/阈值触发写入到当天 `.log` 文件。
class PDLog {
  static PDLogConfig _config = const PDLogConfig();

  /// 设置全局日志配置。
  static void configure(PDLogConfig config) {
    _config = config;
    // 配置 Dart 侧文件写入器
    DartFileLogger.instance.configure(
      enabled: _config.nativeFileLoggingEnabled,
      flushIntervalMs: _config.nativeFileLoggingFlushIntervalMs,
      maxBufferEntries: _config.nativeFileLoggingMaxBufferEntries,
      maxBufferBytes: _config.nativeFileLoggingMaxBufferBytes,
    );

    // 配置事件总线去重窗口与移动端轮询间隔。
    FileEventBus.instance.setDedupeWindowMs(_config.fileEventDedupeWindowMs);
    FileWatchManager.instance
        .setPollIntervalMs(_config.mobileWatchPollingIntervalMs);

    // 如果配置了滚动策略，立即执行一次清理（异步）。
    if (_config.logRetentionStrategy != LogRetentionStrategy.none &&
        _config.logRetentionCount > 0) {
      LogRotation.enforce(
        strategy: _config.logRetentionStrategy,
        count: _config.logRetentionCount,
      );
    }
  }

  /// 更新全局日志配置的部分选项（仅修改传入的字段）。
  static void updateConfigure({
    bool? enabled,
    LogLevel? minLevel,
    String? defaultTag,
    bool? useConsole,
    bool? showTimestamp,
    bool? ansiEnabled,
    bool? showCaller,
    bool? nativeFileLoggingEnabled,
    int? nativeFileLoggingFlushIntervalMs,
    int? nativeFileLoggingMaxBufferEntries,
    int? nativeFileLoggingMaxBufferBytes,
    Map<LogLevel, LogStyleConfig>? logStyles,
    LogLevel? fileLoggingMinLevel,
    LogRetentionStrategy? logRetentionStrategy,
    int? logRetentionCount,
  }) {
    _config = _config.copyWith(
      enabled: enabled,
      minLevel: minLevel,
      defaultTag: defaultTag,
      useConsole: useConsole,
      showTimestamp: showTimestamp,
      ansiEnabled: ansiEnabled,
      showCaller: showCaller,
      nativeFileLoggingEnabled: nativeFileLoggingEnabled,
      nativeFileLoggingFlushIntervalMs: nativeFileLoggingFlushIntervalMs,
      nativeFileLoggingMaxBufferEntries: nativeFileLoggingMaxBufferEntries,
      nativeFileLoggingMaxBufferBytes: nativeFileLoggingMaxBufferBytes,
      logStyles: logStyles,
      fileLoggingMinLevel: fileLoggingMinLevel,
      logRetentionStrategy: logRetentionStrategy,
      logRetentionCount: logRetentionCount,
    );
    // 同步 Dart 写入器配置
    DartFileLogger.instance.configure(
      enabled: _config.nativeFileLoggingEnabled,
      flushIntervalMs: _config.nativeFileLoggingFlushIntervalMs,
      maxBufferEntries: _config.nativeFileLoggingMaxBufferEntries,
      maxBufferBytes: _config.nativeFileLoggingMaxBufferBytes,
    );

    // 动态更新事件总线去重窗口与移动端轮询间隔。
    FileEventBus.instance.setDedupeWindowMs(
      _config.fileEventDedupeWindowMs,
    );
    FileWatchManager.instance.setPollIntervalMs(
      _config.mobileWatchPollingIntervalMs,
    );

    // 如果配置了滚动策略，立即执行一次清理（异步）。
    if (_config.logRetentionStrategy != LogRetentionStrategy.none &&
        _config.logRetentionCount > 0) {
      LogRotation.enforce(
        strategy: _config.logRetentionStrategy,
        count: _config.logRetentionCount,
      );
    }
  }

  /// 获取平台版本信息（Dart-only）。
  static Future<String?> getPlatformVersion() {
    return platformService.getPlatformVersion();
  }

  /// 仅触发 Dart 写入器刷盘（平台侧不再参与）。
  static Future<void> flushNativeLogs() {
    return DartFileLogger.instance.flushNow();
  }

  /// 获取日志根目录路径（由各平台实现决定）。
  static Future<String?> logRootPath() {
    return platformService.getLogRootPath();
  }

  /// 获取日志文件夹的第一级结构（年份文件夹列表，Dart 实现，不递归）。
  /// 返回示例：`["/data/.../pd_log/2025", "/data/.../pd_log/2024"]`。
  static Future<List<String>> listYearFolders() async {
    final root = await logRootPath();
    if (root == null || root.isEmpty) return const [];
    final dir = Directory(root);
    if (!dir.existsSync()) return const [];
    final entries = dir.listSync(recursive: false, followLinks: false);
    final List<String> years = [];
    for (final e in entries) {
      if (e is Directory) {
        final name = e.path.split(Platform.pathSeparator).last;
        if (RegExp(r'^\d{4}$').hasMatch(name)) {
          years.add(e.path);
        }
      }
    }
    // 新到旧排序（路径名为年份）
    years.sort((a, b) => b.compareTo(a));
    return years;
  }

  /// 列出所有日志文件及其元信息。
  static Future<List<PDLogFile>> listLogFiles({ListOptions? options}) async {
    final root = await logRootPath();
    if (root == null || root.isEmpty) return const [];
    final dir = Directory(root);
    if (!dir.existsSync()) return const [];
    final List<PDLogFile> files = [];
    final entries = dir.listSync(recursive: true, followLinks: false);
    for (final e in entries) {
      if (e is File && e.path.endsWith('.log')) {
        try {
          final stat = e.statSync();
          files.add(
            PDLogFile(
              path: e.path,
              sizeBytes: stat.size,
              modifiedMs: stat.modified.millisecondsSinceEpoch,
            ),
          );
        } catch (_) {
          // ignore single file stat errors
        }
      }
    }
    // 同步快照
    await LogLedger.syncFromFiles(files);
    return LogQuery.applyOptions(files, options);
  }

  /// 统计日志总大小（字节）。
  static Future<int> totalLogSize() async {
    final files = await listLogFiles();
    return files.fold<int>(0, (sum, f) => sum + f.sizeBytes);
  }

  /// 检查指定日期对应的日志文件是否存在，并返回其绝对路径。
  ///
  /// - 路径结构（自 `0.5.0` 起）：`/<year>/<month>/<day>.log`；
  /// - 若根路径不可用或文件不存在，返回空字符串；
  /// - 该方法不直接访问文件系统，而是基于 [listLogFiles] 的结果匹配。
  ///
  /// 示例：
  /// ```dart
  /// final path = await PDLog.logFilePathIfExists(DateTime(2025, 1, 19));
  /// if (path.isNotEmpty) {
  ///   // 读取或处理该日志文件
  /// }
  /// ```
  static Future<String> logFilePathIfExists(
    DateTime date,
  ) async {
    final root = await logRootPath();
    if (root == null || root.isEmpty) return '';
    final files = await listLogFiles();
    return LogQuery.findDateFilePath(root, files, date);
  }

  /// 根据指定年份来查询日志文件。
  /// - 返回该年份目录（`/<year>/...`）下的所有 `.log` 文件；
  /// - 若根路径不可用或指定年份目录不存在，则返回空列表。
  static Future<List<PDLogFile>> listLogFilesByYear(
    int year, {
    ListOptions? options,
  }) async {
    final root = await logRootPath();
    if (root == null || root.isEmpty) return const [];
    final all = await listLogFiles();
    final subset = LogQuery.byYear(root, all, year);
    // 子集也进行快照同步（保持最新尺寸与时间）
    await LogLedger.syncFromFiles(subset);
    return LogQuery.applyOptions(subset, options);
  }

  /// 根据指定年份与月份来查询日志文件。
  /// - 返回该年份/月目录（`/<year>/<month>/...`）下的所有 `.log` 文件；
  /// - 若根路径不可用或指定的年份/月目录不存在，则返回空列表。
  static Future<List<PDLogFile>> listLogFilesByYearMonth(
    int year,
    int month, {
    ListOptions? options,
  }) async {
    final root = await logRootPath();
    if (root == null || root.isEmpty) return const [];
    final all = await listLogFiles();
    final subset = LogQuery.byYearMonth(root, all, year, month);
    await LogLedger.syncFromFiles(subset);
    return LogQuery.applyOptions(subset, options);
  }

  /// 删除指定日志文件。
  static Future<bool> deleteLogFile(String path) async {
    try {
      final f = File(path);
      if (!f.existsSync()) return false;
      await f.delete();
      await LogLedger.recordDeletion(path);
      // 内部立即广播删除事件，移动端轮询可实现即刻可见；
      // 目录 watcher 会产生重复事件，交由总线去重。
      FileEventBus.instance.emitDeleted(path);
      return true;
    } catch (_) {
      return false;
    }
  }

  /// 删除所有日志文件，返回删除数量。
  static Future<int> deleteAllLogFiles() async {
    final root = await logRootPath();
    if (root == null || root.isEmpty) return 0;
    final dir = Directory(root);
    if (!dir.existsSync()) return 0;
    int deleted = 0;
    final entries = dir.listSync(recursive: true, followLinks: false);
    for (final e in entries) {
      if (e is File && e.path.endsWith('.log')) {
        try {
          await e.delete();
          deleted++;
          await LogLedger.recordDeletion(e.path);
          FileEventBus.instance.emitDeleted(e.path);
        } catch (_) {
          // skip failures
        }
      }
    }
    // 同步剩余文件快照
    final remain = await listLogFiles();
    await LogLedger.syncFromFiles(remain);
    return deleted;
  }

  /// 立即执行一次滚动策略清理，返回删除的文件数。
  ///
  /// - 可通过 [strategy] 与 [count] 临时覆盖全局配置。
  /// - 若未传则使用当前全局配置；当策略为 `none` 或数量 <= 0 时不做任何操作。
  static Future<int> enforceRotation({
    LogRetentionStrategy? strategy,
    int? count,
  }) {
    final s = strategy ?? _config.logRetentionStrategy;
    final c = count ?? _config.logRetentionCount;
    if (s == LogRetentionStrategy.none || c <= 0) return Future.value(0);
    return LogRotation.enforce(strategy: s, count: c);
  }

  /// 上传状态：标记开始上传。
  static Future<void> markUploadStarted(String path) {
    return LogLedger.markUploadStarted(path);
  }

  /// 上传状态：标记上传成功。
  static Future<void> markUploadSuccess(String path) {
    return LogLedger.markUploadSuccess(path);
  }

  /// 上传状态：标记上传失败并记录错误。
  static Future<void> markUploadFailed(String path, [String? error]) {
    return LogLedger.markUploadFailed(path, error);
  }

  /// 查询快照（包括已删除的历史记录，可按选项排序与分页）。
  static Future<List<LogRecord>> listSummary({
    ListOptions? options,
    UploadState? uploadState,
  }) {
    return LogLedger.listSummary(options: options, uploadState: uploadState);
  }

  /// 返回日志根目录的树状结构字符串（便于外部开发者自行打印）。
  /// - 移动/桌面平台将递归遍历到指定深度；Web 平台返回占位说明。
  static Future<String> fileTreeString({int maxDepth = 4}) {
    return LogLedger.fileTreeAsText(maxDepth: maxDepth);
  }

  /// 返回元数据文件 `pd_log_ledger.jsonl` 的原始文本内容。
  /// - 若文件不存在或根路径不可用，返回可读错误信息；Web 平台返回占位说明。
  static Future<String> metaLedgerContent() {
    return LogLedger.readLedgerContent();
  }

  /// 返回元数据文件 `pd_log_summary.json` 的原始文本内容。
  /// - 若文件不存在或根路径不可用，返回可读错误信息；Web 平台返回占位说明。
  static Future<String> metaSummaryContent() {
    return LogLedger.readSummaryContent();
  }

  /// 读取指定日志文件的文本内容并返回。
  /// - 若路径不存在或平台不支持（Web），返回可读错误信息；
  static Future<String> readFileContent(String path) {
    return LogLedger.readFileContent(path);
  }

  /// 订阅平台侧日志文件事件（创建/删除）。
  /// 返回事件流，事件为 `Map`：`type`, `path`, `sizeBytes`, `modifiedMs`, `tsMs`。
  static Stream<Map<String, dynamic>> fileEvents() {
    // 切换到 Dart 侧事件总线：混合实现（桌面 watcher + 移动轮询 + 内部触发）。
    // 懒启动监听器以避免不必要的资源占用。
    // Web 平台为 no-op，仍返回可监听的空流。
    // 向后兼容：保持事件 Map 结构不变。
    // 启动监听器（仅一次）
    FileWatchManager.instance.startIfNeeded();
    return FileEventBus.instance.stream;
  }

  /// 输出 `verbose` 级别日志。
  ///
  /// 参数：
  /// - [message]：要输出的内容，支持任意类型；`Map`/`Iterable` 将自动转为 JSON。
  /// - [tag]：可选标签，未传入时使用全局配置中的默认标签。
  static void v(Object? message, {String? tag}) {
    LogUtils.log(LogLevel.verbose, message, tag: tag, config: _config);
  }

  /// 输出 `debug` 级别日志。
  ///
  /// 参数同 [v]。
  static void d(Object? message, {String? tag}) {
    LogUtils.log(LogLevel.debug, message, tag: tag, config: _config);
  }

  /// 输出 `info` 级别日志。
  ///
  /// 参数同 [v]。
  static void i(Object? message, {String? tag}) {
    LogUtils.log(LogLevel.info, message, tag: tag, config: _config);
  }

  /// 输出 `warn` 级别日志。
  ///
  /// 参数同 [v]。
  static void w(Object? message, {String? tag}) {
    LogUtils.log(LogLevel.warn, message, tag: tag, config: _config);
  }

  /// 输出 `error` 级别日志。
  ///
  /// 参数同 [v]。
  static void e(Object? message, {String? tag}) {
    LogUtils.log(LogLevel.error, message, tag: tag, config: _config);
  }

  /// 输出自定义行为的日志（可临时覆盖全局配置）。
  ///
  /// 参数：
  /// - [message]：要打印的内容；
  /// - [tag]：日志标签；
  /// - [useConsole]：是否在 Dart 控制台打印；
  /// - [toFile]：是否写入本地文件（由 Dart 写入器管理）；
  /// - [showTimestamp]：是否显示时间戳；
  /// - [style]：日志样式（前景色/背景色/文本样式），优先级最高；
  ///   - 参考：[LogStyleConfig] 和默认样式映射 [PDLogConfig.logStyles]；
  static void out(
    Object? message, {
    LogLevel? level,
    String? tag,
    bool? useConsole,
    bool? toFile,
    bool? showTimestamp,
    LogStyleConfig? style,
  }) {
    LogUtils.log(
      level ?? LogLevel.verbose,
      message,
      tag: tag,
      useConsole: useConsole,
      toFile: toFile,
      showTimestamp: showTimestamp,
      style: style,
      config: _config,
    );
  }

  /// 将可被json序列化的对象转为美化后的json string
  static String formatJson(Object? message) {
    return LogUtils.formatJson(message);
  }

  /// 格式化打印
  /// - 平台控制台打印，避免内容过长被截断
  static void formated(
    Object? message, {
    LogLevel? level,
    String? tag,
    bool? useConsole,
    bool? toFile,
    bool? showTimestamp,
    bool? showCaller,
    LogStyleConfig? style,
  }) {
    final jsonString = PDLog.formatJson(message);
    LogUtils.log(
      level ?? LogLevel.verbose,
      '\n$jsonString',
      tag: tag,
      useConsole: useConsole,
      toFile: toFile ?? false,
      showTimestamp: showTimestamp,
      showCaller: showCaller,
      style: style,
      config: _config,
    );
  }
}
